package spring.cloud.tasks.tasks_manager.schedule;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.DateUtils;
import spring.cloud.tasks.common.curator.Curator;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Setter
@Getter
public class TaskFireDateTimeAndPreAssignDateTimeManager {
    protected ScheduleManager scheduleManager;
    private final String nameSpace;
    protected Curator curator;
    public Context context = new Context();

    public TaskFireDateTimeAndPreAssignDateTimeManager(ScheduleManager scheduleManager, String nameSpace, Curator curator) {
        this.scheduleManager = scheduleManager;
        this.nameSpace = nameSpace;
        this.curator = curator;

    }

    /**
     * 属性对象化，这个类不要忘外面提。。。
     */
    public static class Context {
        public volatile List<String> taskIdList = new ArrayList<>();
        public volatile List<String> enableTaskIdList = new ArrayList<>();
        public volatile List<String> pauseTaskIdList = new ArrayList<>();
        public volatile ConcurrentHashMap<String, TaskFireDateTimeAndPreAssignDateTimeListHolder> taskIdToFireDateTimeAndPreAssignDateTimeListContextMap = new ConcurrentHashMap<String, TaskFireDateTimeAndPreAssignDateTimeListHolder>();
    }

    public void refresh() throws Exception {

        TaskConfigurationManager taskConfigurationManager = scheduleManager.taskConfigurationManager;
        List<String> $taskIdList$ = taskConfigurationManager.getTaskIdList();//配置管理
        scheduleManager.taskIdListContext.refresh(curator);
        TaskIdListContext.TaskIdLists taskIdLists = scheduleManager.taskIdListContext.taskIdLists;
        List<String> taskIdList = taskIdLists.taskIdList;
        List<String> enableTaskIdList = taskIdLists.enableTaskIdList;
        List<String> pauseTaskIdList = taskIdLists.pauseTaskIdList;
        //
        Context context = new Context();
        ConcurrentHashMap<String, TaskFireDateTimeAndPreAssignDateTimeListHolder> newMap = context.taskIdToFireDateTimeAndPreAssignDateTimeListContextMap;
        //
        //先拉取所有任务的时间信息。直接从缓存里面获取。专门一个线程进行汇总
        ConcurrentHashMap<String, ExecutableDateTimePointBaseInfo> taskIdToExecutableDateTimePointBaseInfoMap = taskConfigurationManager.taskIdToExecutableDateTimePointBaseInfoMap;
        //
        ConcurrentHashMap<String, TaskFireDateTimeAndPreAssignDateTimeListHolder> oldMap = this.context.taskIdToFireDateTimeAndPreAssignDateTimeListContextMap;
        Date nowDate = new Date();
        for (String taskId : taskIdList) {//
            if (!($taskIdList$.contains(taskId) &&//
                    taskIdList.contains(taskId) && //
                    enableTaskIdList.contains(taskId) //
                    && !pauseTaskIdList.contains(taskId))) {//
                log.warn("不满足任务执行条件[1调度器有对应的任务配置信息，2该任务处于启用状态 3该任务没有暂停]" + taskId);
                continue;
            } else {
                //
                ExecutableDateTimePointBaseInfo executableDateTimePointBaseInfo = taskIdToExecutableDateTimePointBaseInfoMap.get(taskId);
                if (executableDateTimePointBaseInfo == null) {
                    continue;//配置线程出了问题
                }
                long version = executableDateTimePointBaseInfo.getVersion();
                String cronExpression = executableDateTimePointBaseInfo.getCronExpression();
                String pauseDatePeriod = executableDateTimePointBaseInfo.getPauseDatePeriod();
                String pauseTimePeriod = executableDateTimePointBaseInfo.getPauseTimePeriod();
                Integer preAssignMinutes = executableDateTimePointBaseInfo.getPreAssignMinutes();
                //
                TaskFireDateTimeAndPreAssignDateTimeListHolder oldHolder = oldMap.get(taskId);
                if (oldHolder == null) {
                    TaskFireDateTimeAndPreAssignDateTimeListHolder holder = new TaskFireDateTimeAndPreAssignDateTimeListHolder(taskId);
                    holder.compute(version, cronExpression, pauseDatePeriod, pauseTimePeriod, preAssignMinutes);
                    newMap.put(taskId, holder);//替换
                    continue;
                } else {
                    long oldVersion = oldHolder.getSuspendableCronExpression().getVersion();
                    if (!(oldVersion == version)) {
                        TaskFireDateTimeAndPreAssignDateTimeListHolder holder = new TaskFireDateTimeAndPreAssignDateTimeListHolder(taskId);
                        holder.compute(version, cronExpression, pauseDatePeriod, pauseTimePeriod, preAssignMinutes);
                        newMap.put(taskId, holder);//替换
                        continue;
                    } else {
                        boolean needReCompute = true;
                        List<FireDateTimeAndPreAssignDateTime> list = oldHolder.getFireDateTimeAndPreAssignDateTimeList();
                        int count = 0;
                        for (FireDateTimeAndPreAssignDateTime fireDateTimeAndPreAssignDateTime : list) {
                            if (fireDateTimeAndPreAssignDateTime.getNextFireDate().getTime() > nowDate.getTime()) {
                                if (fireDateTimeAndPreAssignDateTime.getNextFireDate().getTime() >= nowDate.getTime() + DateUtils.MINUTE * TaskFireDateTimeAndPreAssignDateTimeListHolder.$24_value) {
                                    newMap.put(taskId, oldHolder);//替换
                                    needReCompute = false;
                                    break;
                                }
                                count++;
                                if (fireDateTimeAndPreAssignDateTime.getNextFireDate().getTime() >= nowDate.getTime() + DateUtils.MINUTE * TaskFireDateTimeAndPreAssignDateTimeListHolder.$12_value && count >= 3) {
                                    newMap.put(taskId, oldHolder);//替换
                                    needReCompute = false;
                                    break;
                                }
                            }
                        }
                        if (needReCompute) {
                            TaskFireDateTimeAndPreAssignDateTimeListHolder holder = new TaskFireDateTimeAndPreAssignDateTimeListHolder(taskId);
                            holder.compute(version, cronExpression, pauseDatePeriod, pauseTimePeriod, preAssignMinutes);
                            newMap.put(taskId, holder);//替换
                            continue;
                        } else {
                            continue;
                        }

                    }
                }
            }
        }
        //
        //计算完毕的时候再进行总体的替换
        context.taskIdList = taskIdList;
        context.enableTaskIdList = enableTaskIdList;
        context.pauseTaskIdList = pauseTaskIdList;
        context.taskIdToFireDateTimeAndPreAssignDateTimeListContextMap = newMap;
        this.context = context;
        //需要将执行计划同步到ZK上面
    }


}
